#include <amxmodx>
#include <amxmisc>
#include <cstrike>
#include <fakemeta>

#define ACCESS_LEVEL ADMIN_LEVEL_B

new const lightning_sprite[] = "sprites/lgtning.spr"
new const sound_file[] = "weapons/electro5.wav"

new const Float:origin_offsets[45] =
{
	0.0,0.0,0.0,
	0.0,0.0,32.0,
	0.0,0.0,-32.0,
	12.0,0.0,0.0,
	-12.0,0.0,0.0,
	0.0,12.0,0.0,
	0.0,-12.0,0.0,
	12.0,0.0,32.0,
	-12.0,0.0,32.0,
	0.0,12.0,32.0,
	0.0,-12.0,32.0,
	12.0,0.0,-32.0,
	-12.0,0.0,-32.0,
	0.0,12.0,-32.0,
	0.0,-12.0,-32.0
}

new spriteindex
new DeathMsg

new bool:can_shoot[33]

new enabled_pcvar
new damage_pcvar
new distance_pcvar
new head_damage_pcvar

public plugin_init()
{
	register_plugin("Admin Lightning","0.2","muxah")
	register_forward(FM_PlayerPreThink,"Forward_Think")
	register_clcmd("+lightning", "fire", ACCESS_LEVEL)
	register_clcmd("-lightning", "stop", ACCESS_LEVEL)

	enabled_pcvar = register_cvar("lg_awp_enabled","1")
	damage_pcvar = register_cvar("lg_awp_damage","500.0")
	distance_pcvar = register_cvar("lg_awp_distance","100.0")
	head_damage_pcvar = register_cvar("lg_awp_hs_damage","999.0")

	DeathMsg = get_user_msgid("DeathMsg")
}

public plugin_precache()
{
	spriteindex = precache_model(lightning_sprite)
	precache_sound(sound_file)
}

public fire(id, level, cid)
{
	if (!cmd_access(id, level, cid, 1))
	return PLUGIN_HANDLED
	 
	can_shoot[id] = true
	client_print(id, print_center, "Mo4u 4uTaKoB!!!")
	return PLUGIN_CONTINUE   
}


public stop(id)
{

	can_shoot[id] = false

}

public Forward_Think(id)
{
	if(get_pcvar_num(enabled_pcvar))
	{

		if(can_shoot[id])
		{
			//Get Player's nozzle origin
			//And Where he shot
			new I_player_origin[3], I_end_origin[3]
			new Float:player_origin[3], Float:end_origin[3]
			pev(id,pev_origin,player_origin)
			get_user_origin(id,I_player_origin,1)
			get_user_origin(id,I_end_origin,3)
			IVecFVec(I_end_origin,end_origin)
			IVecFVec(I_player_origin,player_origin)

			//Make a Lightning Beam between those 2 locations
			message_begin(MSG_BROADCAST, SVC_TEMPENTITY) 
			write_byte(0)		//TE_BEAMPOINTS
			write_coord(I_player_origin[0])	// start position
			write_coord(I_player_origin[1])
			write_coord(I_player_origin[2])
			write_coord(I_end_origin[0])	// end position 
			write_coord(I_end_origin[1])
			write_coord(I_end_origin[2])
			write_short(spriteindex)
			write_byte(1)	// framestart
			write_byte(1)	// framerate
			write_byte(2)	// life in 0.1's
			write_byte(40)	// width
			write_byte(0)	// noise
			write_byte(255)
			write_byte(255)
			write_byte(255)
			write_byte(200)	// brightness
			write_byte(0)	// speed
			message_end()

			emit_sound(id,CHAN_VOICE,sound_file,VOL_NORM, ATTN_NORM,0,PITCH_NORM)

			//Possible targets to have been shot
			new players[32], num
			get_players(players,num,"h")

			new Float:target_origin[3]
			new Float:target_origin2[3]
			new Float:hit[3]

			new aiment, bodypart
			get_user_aiming(id,aiment,bodypart)
			new CsTeams:id_team = cs_get_user_team(id)

			for(new i=0;i<num;i++)
			{
				//Not self / same team
				if(players[i]!=id)
				{
					pev(players[i],pev_origin,target_origin2)
					//Loop through all offset origins
					for(new current_offset=0;current_offset<15;current_offset++)
					{
						target_origin[0] = target_origin2[0] + origin_offsets[current_offset*3 + 0]
						target_origin[1] = target_origin2[1] + origin_offsets[current_offset*3 + 1]
						target_origin[2] = target_origin2[2] + origin_offsets[current_offset*3 + 2]

						//Is the target able to be hit by the player (or is there a wall or something between them)
						engfunc(EngFunc_TraceLine,player_origin,target_origin,1,id,0)
						get_tr2(0,TR_vecEndPos,hit)
						if((hit[0]==target_origin[0] && hit[1]==target_origin[1] && hit[2]==target_origin[2]) || aiment==players[i])
						{
							//Calculate if in FOV (Because arctan calculations assume the lines are continuous, however they really only extend from player forward, not backward)
							static Float:angles[3], Float:diff[3], Float:reciprocalsq, Float:norm[3], Float:dot, Float:fov
							pev(id, pev_angles, angles)
							engfunc(EngFunc_MakeVectors, angles)
							global_get(glb_v_forward, angles)
							angles[2] = 0.0

							diff[0] = target_origin[0] - player_origin[0]
							diff[1] = target_origin[1] - player_origin[1]
							diff[2] = target_origin[2] - player_origin[2]
							//diff[2] = 0.0// - for 2D viewcone

							reciprocalsq = 1.0 / floatsqroot(diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2])
							norm[0] = diff[0] * reciprocalsq
							norm[1] = diff[1] * reciprocalsq
							norm[2] = diff[2] * reciprocalsq

							dot = norm[0]*angles[0] + norm[1]*angles[1] + norm[2]*angles[2]
							pev(id, pev_fov, fov)
							if(dot >= floatcos(fov * 3.1415926535 / 360.0))
							{
	
								//Calculate if target is close enough to the lightning-rail to get hurt
								new Float:slope[2][2]
								slope[0][0] = (player_origin[1] - end_origin[1]) / (player_origin[0] - end_origin[0])
								slope[1][0] = (player_origin[1] - target_origin[1]) / (player_origin[0] - target_origin[0])

								slope[0][1] = (player_origin[1] - end_origin[1]) / (player_origin[2] - end_origin[2])
								slope[1][1] = (player_origin[1] - target_origin[1]) / (player_origin[2] - target_origin[2])

								new Float:tan[3][2]
								new Float:sin[2]
								tan[0][0] = floatatan(slope[1][0],degrees)
								tan[1][0] = floatatan(slope[0][0],degrees)
								tan[2][0] = floatabs(tan[0][0] - tan[1][0])
								sin[0] = floatsin(tan[2][0],degrees)

								tan[0][1] = floatatan(slope[1][1],degrees)
								tan[1][1] = floatatan(slope[0][1],degrees)
								tan[2][1] = floatabs(tan[0][1] - tan[1][1])
								sin[1] = floatsin(tan[2][1],degrees)

								//If that position is close enough to the target for him to be hit by the lightning
								if(sin[0] * get_distance_f(target_origin,player_origin) <= get_pcvar_float(distance_pcvar) && sin[1] * get_distance_f(target_origin,player_origin) <= get_pcvar_float(distance_pcvar))
								{
									new hs = 0
									new old_msgblock = get_msg_block(DeathMsg)
									set_msg_block(DeathMsg,BLOCK_ONCE)
									//If id is not aiming at target's head
									if(players[i]!=aiment || bodypart!=1)
									{
										//Make a Lightning Beam on the hit target
										message_begin(MSG_BROADCAST, SVC_TEMPENTITY) 
										write_byte(0)		//TE_BEAMPOINTS
										write_coord(floatround(target_origin[0]) + 32)	// start position
										write_coord(floatround(target_origin[1]) + 32)
										write_coord(floatround(target_origin[2]) + 32)
										write_coord(floatround(target_origin[0]) - 32)	// end position 
										write_coord(floatround(target_origin[1]) - 32)
										write_coord(floatround(target_origin[2]) - 32)
										write_short(spriteindex)
										write_byte(1)	// framestart
										write_byte(1)	// framerate
										write_byte(2)	// life in 0.1's
										write_byte(200)	// width
										write_byte(0)	// noise
										write_byte(255)
										write_byte(255)
										write_byte(255)
										write_byte(200)	// brightness
										write_byte(0)	// speed
										message_end()
										
										client_print(id, print_center, "Mo4u 4uTaKoB!!!")
										
										fm_fakedamage(players[i],id,get_pcvar_float(damage_pcvar),DMG_BULLET)
									}
									else
									{
										hs = 1
										fm_fakedamage(players[i],id,get_pcvar_float(head_damage_pcvar),DMG_BULLET)
									}
									set_msg_block(DeathMsg,old_msgblock)

									//If player died produce death message
									if(!is_user_alive(players[i]))
									{
										make_deathmsg(id,players[i],hs,"awp")
									}
								}
							}
							break;
						}
					}
				}
			}
		}
	}
}

//From VEN
stock fm_fakedamage(victim,attacker, Float:takedmgdamage, damagetype)
{
	new entity = engfunc(EngFunc_CreateNamedEntity,engfunc(EngFunc_AllocString,"trigger_hurt"))

	new value[16]
	float_to_str(takedmgdamage * 2, value, 15)
	set_kvd(0, KV_ClassName,"trigger_hurt")
	set_kvd(0, KV_KeyName, "dmg")
	set_kvd(0, KV_Value, value)
	set_kvd(0, KV_fHandled, 0)
	dllfunc(DLLFunc_KeyValue,entity,0)

	num_to_str(damagetype, value, 15)
	set_kvd(0, KV_ClassName,"trigger_hurt")
	set_kvd(0, KV_KeyName, "damagetype")
	set_kvd(0, KV_Value, value)
	set_kvd(0, KV_fHandled, 0)
	dllfunc(DLLFunc_KeyValue,entity,0)

	set_kvd(0, KV_ClassName,"trigger_hurt")
	set_kvd(0, KV_KeyName, "origin")
	set_kvd(0, KV_Value, "8192 8192 8192")
	set_kvd(0, KV_fHandled, 0)
	dllfunc(DLLFunc_KeyValue,entity,0)

	dllfunc(DLLFunc_Spawn,entity)

	set_pev(entity,pev_classname,"Lightning")
	set_pev(entity,pev_owner,attacker)
	dllfunc(DLLFunc_Touch,entity,victim)
	engfunc(EngFunc_RemoveEntity,entity)

	return 1
}